<?php

declare(strict_types=1);

namespace app\service\cart;

use app\model\Cart;
use app\model\CartStock;
use app\model\Prod;
use app\model\User;
use app\service\notify\CreateNotifyService;
use app\util\GenNoUtil;
use InvalidArgumentException;
use RuntimeException;
use think\facade\Log;
use think\Paginator;

/**
 * 现货核实业务逻辑
 */
class StockVerificationService
{
    protected CreateNotifyService $notifyService;

    public function __construct(CreateNotifyService $notifyService)
    {
        $this->notifyService = $notifyService;
    }

    /**
     * 买家发起现货核实
     *
     * @param array $payload
     */
    public function create(array $payload): CartStock
    {
        $cartId = (int) ($payload['cart_id'] ?? 0);
        $buyerId = (int) ($payload['buyer_id'] ?? 0);
        if ($cartId <= 0 || $buyerId <= 0) {
            throw new InvalidArgumentException('参数不合法');
        }

        return $this->createFromCart($cartId, $buyerId, $payload);
    }

    public function createFromCart(int $cartId, int $buyerId, array $payload = []): CartStock
    {
        /** @var Cart|null $cart */
        $cart = Cart::find($cartId);
        if (!$cart) {
            throw new InvalidArgumentException('购物车记录不存在');
        }

        if ((int) $cart->buyer_id !== $buyerId) {
            throw new InvalidArgumentException('无权操作该购物车记录');
        }

        $data = $this->buildRecordFromCart($cart, $buyerId, $payload);

        /** @var Prod|null $product */
        $product = Prod::find($data['product_id']);
        if (!$product) {
            throw new InvalidArgumentException('商品不存在');
        }

        $data['seller_org_id'] = $product->seller_org_id;
        $data['seller_id'] = $product->seller_user_id;
        $data['region_id'] = $product->region_id;
        $data['snapshot_price'] = $product->default_price;
        $data['snapshot_currency'] = 'CNY';
        $data['snapshot_product'] = [
            'title' => $product->title,
            'model' => $product->model,
            'cover_image' => $product->cover_image,
            'unit' => $product->unit,
        ];

        $buyerMember = $this->resolveBuyerOrg($data['buyer_id']);
        $data['buyer_org_id'] = $buyerMember['org_id'] ?? null;

        $data['verify_no'] = $this->generateVerifyNo();
        $data['buyer_time'] = date('Y-m-d H:i:s');
        $data['status'] = CartStock::STATUS_PENDING;
        $data['seller_qty'] = 0;
        $data['seller_media'] = [];

        /** @var CartStock $record */
        $record = CartStock::create($data);
        $record = $record->refresh();

        $cart->status = 2;
        $cart->save();

        $this->notifySeller($record, 'spotcheck');

        return $record;
    }

    /**
     * 卖家回复核实结果
     *
     * @param int $id
     * @param array $payload
     */
    public function reply(int $id, array $payload): CartStock
    {
        /** @var CartStock|null $record */
        $record = CartStock::find($id);
        if (!$record) {
            throw new RuntimeException('核实单不存在');
        }

        $sellerId = (int)($payload['seller_id'] ?? 0);
        if ($record->seller_id) {
            if ($sellerId <= 0 || $sellerId !== (int)$record->seller_id) {
                throw new InvalidArgumentException('无权回复该核实单');
            }
        }

        if ($record->status === CartStock::STATUS_CANCELLED) {
            throw new RuntimeException('核实单已取消，无法回复');
        }

        $status = isset($payload['status']) ? (int)$payload['status'] : CartStock::STATUS_VERIFIED;
        if (!in_array($status, [CartStock::STATUS_VERIFIED, CartStock::STATUS_REJECTED], true)) {
            throw new InvalidArgumentException('状态不合法');
        }

        $sellerQty = isset($payload['seller_qty']) ? (int)$payload['seller_qty'] : null;
        if ($status === CartStock::STATUS_VERIFIED) {
            if ($sellerQty === null || $sellerQty <= 0) {
                throw new InvalidArgumentException('卖家确认数量必须大于0');
            }
        } else {
            $sellerQty = 0;
        }

        $record->seller_qty = $sellerQty;
        $record->seller_remark = (string)($payload['seller_remark'] ?? $record->seller_remark ?? '');
        if (!empty($payload['seller_media'])) {
            $media = $payload['seller_media'];
            if (!is_array($media)) {
                $media = [$media];
            }
            $record->seller_media = $media;
        }
        $record->seller_time = date('Y-m-d H:i:s');
        $record->status = $status;
        $record->save();

        $this->notifyBuyer($record, 'spotcheck_reply');

        return $record;
    }

    /**
     * 买家取消核实
     *
     * @param int $id
     * @param int $buyerId
     */
    public function cancel(int $id, int $buyerId): CartStock
    {
        /** @var CartStock|null $record */
        $record = CartStock::find($id);
        if (!$record) {
            throw new RuntimeException('核实单不存在');
        }

        if ($record->buyer_id !== $buyerId) {
            throw new InvalidArgumentException('无权取消该核实单');
        }

        if ($record->status === CartStock::STATUS_CANCELLED) {
            return $record;
        }

        if ($record->status !== CartStock::STATUS_PENDING) {
            throw new RuntimeException('核实单当前状态不允许取消');
        }

        $record->status = CartStock::STATUS_CANCELLED;
        $record->save();

        return $record;
    }

    /**
     * 获取核实单详情
     */
    public function get(int $id): CartStock
    {
        /** @var CartStock|null $record */
        $record = CartStock::find($id);
        if (!$record) {
            throw new RuntimeException('核实单不存在');
        }

        return $record;
    }

    /**
     * 分页列表
     *
     * @param array $filters
     * @param int $page
     * @param int $pageSize
     */
    public function paginate(array $filters, int $page = 1, int $pageSize = 20): array
    {
        $paginator = $this->paginateRecords($filters, $page, $pageSize);

        return [
            'list' => array_map(static fn($item) => $item->toArray(), $paginator->items()),
            'total' => (int) $paginator->total(),
        ];
    }

    public function paginateRecords(array $filters, int $page = 1, int $pageSize = 20, array $with = []): Paginator
    {
        $query = CartStock::with($with)->order('id', 'desc');

        if (!empty($filters['keyword'])) {
            $keyword = trim((string) $filters['keyword']);
            $query->where(static function ($subQuery) use ($keyword) {
                $subQuery->whereLike('verify_no', '%' . $keyword . '%')
                    ->whereOr('buyer_remark', 'like', '%' . $keyword . '%')
                    ->whereOr('seller_remark', 'like', '%' . $keyword . '%');
            });
            unset($filters['keyword']);
        }

        foreach ($filters as $field => $value) {
            if ($value === '' || $value === null) {
                continue;
            }

            if ($field === 'status' && is_array($value)) {
                $query->whereIn('status', $value);
                continue;
            }

            if ($field === 'buyer_media' || $field === 'seller_media') {
                continue;
            }

            $query->where($field, $value);
        }

        return $query->paginate([
            'list_rows' => $pageSize,
            'page' => $page,
        ]);
    }

    public function formatRecord(CartStock $record, string $role = 'admin'): array
    {
        $record->load(['buyer.profile', 'sellerOrg', 'product', 'assistUser.profile', 'region']);

        $data = [
            'id' => (int) $record->id,
            'verify_no' => $record->verify_no,
            'status' => (int) $record->status,
            'status_label' => $this->statusLabel((int) $record->status),
            'buyer_qty' => (int) $record->buyer_qty,
            'buyer_remark' => (string) $record->buyer_remark,
            'buyer_media' => $this->formatMediaOutput($record->buyer_media ?? []),
            'buyer_time' => $record->buyer_time,
            'buyer' => [
                'id' => (int) $record->buyer_id,
                'org_id' => $record->buyer_org_id ? (int) $record->buyer_org_id : null,
            ],
            'seller_qty' => (int) $record->seller_qty,
            'seller_remark' => (string) $record->seller_remark,
            'seller_media' => $this->formatMediaOutput($record->seller_media ?? []),
            'seller_time' => $record->seller_time,
            'seller' => [
                'id' => $record->seller_id ? (int) $record->seller_id : null,
                'org_id' => (int) $record->seller_org_id,
            ],
            'assist_user_id' => $record->assist_user_id ? (int) $record->assist_user_id : null,
            'region_id' => $record->region_id ? (int) $record->region_id : null,
            'audit_status' => (int) $record->audit_status,
            'audit_remark' => (string) $record->audit_remark,
            'audit_time' => $record->audit_time,
            'snapshot_product' => $record->snapshot_product ?? [],
            'product_id' => (int) $record->product_id,
            'sku_id' => $record->sku_id ? (int) $record->sku_id : null,
            'order_id' => $record->order_id ? (int) $record->order_id : null,
            'order_no' => (string) ($record->order_no ?? ''),
            'create_time' => $record->create_time,
            'update_time' => $record->update_time,
        ];

        if ($record->product) {
            $data['product'] = [
                'id' => (int) $record->product->id,
                'title' => $record->product->title,
                'model' => $record->product->model,
            ];
        }

        if ($record->sellerOrg) {
            $data['seller']['name'] = $record->sellerOrg->name;
        }

        if ($record->buyer && $record->buyer->profile) {
            $data['buyer']['name'] = $record->buyer->profile->real_name ?? $record->buyer->phone ?? '';
        }

        if ($record->assistUser) {
            $data['assist_user'] = [
                'id' => (int) $record->assist_user_id,
                'name' => $record->assistUser->profile->real_name ?? $record->assistUser->phone ?? '',
            ];
        }

        if ($record->region) {
            $data['region'] = [
                'id' => (int) $record->region->id,
                'name' => $record->region->name,
            ];
        }

        if ($role === 'buyer') {
            unset($data['seller']['id']);
            unset($data['assist_user']);
        }

        if ($role === 'seller') {
            unset($data['buyer']['name']);
        }

        return $data;
    }

    public function formatCollection(iterable $records, string $role = 'admin'): array
    {
        $results = [];
        foreach ($records as $record) {
            if ($record instanceof CartStock) {
                $results[] = $this->formatRecord($record, $role);
            }
        }

        return $results;
    }

    public function adminUpdate(CartStock $record, array $payload): CartStock
    {
        $data = [];

        if (array_key_exists('assist_user_id', $payload)) {
            $assistId = $payload['assist_user_id'];
            $data['assist_user_id'] = $assistId ? (int) $assistId : null;
        }

        if (array_key_exists('status', $payload)) {
            $status = (int) $payload['status'];
            if (!in_array($status, [CartStock::STATUS_PENDING, CartStock::STATUS_VERIFIED, CartStock::STATUS_REJECTED, CartStock::STATUS_CANCELLED], true)) {
                throw new InvalidArgumentException('状态不合法');
            }
            $data['status'] = $status;
        }

        if (array_key_exists('audit_status', $payload)) {
            $auditStatus = (int) $payload['audit_status'];
            if (!in_array($auditStatus, [0, 1, 2], true)) {
                throw new InvalidArgumentException('审核状态不合法');
            }
            $data['audit_status'] = $auditStatus;
            $data['audit_time'] = date('Y-m-d H:i:s');
        }

        if (isset($payload['audit_remark'])) {
            $data['audit_remark'] = (string) $payload['audit_remark'];
        }

        if (array_key_exists('seller_qty', $payload)) {
            $qty = (int) $payload['seller_qty'];
            if ($qty < 0) {
                throw new InvalidArgumentException('卖家确认数量不合法');
            }
            $data['seller_qty'] = $qty;
        }

        if (array_key_exists('seller_remark', $payload)) {
            $data['seller_remark'] = (string) $payload['seller_remark'];
        }

        if (array_key_exists('seller_media', $payload)) {
            $data['seller_media'] = $this->normalizeMedia($payload['seller_media']);
        }

        if ($data === []) {
            return $record->refresh();
        }

        $record->save($data);

        return $record->refresh();
    }

    /**
     * 校验创建数据
     */
    protected function buildRecordFromCart(Cart $cart, int $buyerId, array $payload): array
    {
        $buyerQty = isset($payload['buyer_qty']) ? (int) $payload['buyer_qty'] : (int) $cart->qty;
        if ($buyerQty <= 0) {
            throw new InvalidArgumentException('需求数量必须大于0');
        }

        $buyerRemark = (string) ($payload['buyer_remark'] ?? $cart->remark ?? '');

        return [
            'buyer_id' => $buyerId,
            'product_id' => (int) $cart->product_id,
            'sku_id' => $cart->sku_id ? (int) $cart->sku_id : null,
            'buyer_qty' => $buyerQty,
            'buyer_remark' => $buyerRemark,
            'buyer_media' => $this->normalizeMedia($payload['buyer_media'] ?? []),
        ];
    }

    /**
     * 生成唯一核实单号
     */
    protected function generateVerifyNo(): string
    {
        do {
            $no = GenNoUtil::verify();
        } while (CartStock::where('verify_no', $no)->find());

        return $no;
    }

    /**
     * 通知卖家
     */
    protected function notifySeller(CartStock $record, string $type): void
    {
        try {
            $this->notifyService->add([
                [
                    'id' => (int)$record->seller_id,
                    'type' => 'seller',
                ]
            ], $type, [
                'verify_no' => $record->verify_no,
                'buyer_id' => $record->buyer_id,
                'seller_id' => $record->seller_id,
                'prod_id' => $record->product_id,
                'buyer_qty' => $record->buyer_qty,
                'status' => $record->status,
            ]);
        } catch (\Throwable $e) {
            Log::error('通知卖家现货核实失败: ' . $e->getMessage(), [
                'verify_no' => $record->verify_no,
                'cart_stock_id' => $record->id ?? null,
            ]);
        }
    }

    /**
     * 通知买家
     */
    protected function notifyBuyer(CartStock $record, string $type): void
    {
        try {
            $this->notifyService->add([
                [
                    'id' => (int)$record->buyer_id,
                    'type' => 'buyer',
                ]
            ], $type, [
                'verify_no' => $record->verify_no,
                'buyer_id' => $record->buyer_id,
                'seller_id' => $record->seller_id,
                'prod_id' => $record->product_id,
                'seller_qty' => $record->seller_qty,
                'status' => $record->status,
            ]);
        } catch (\Throwable $e) {
            Log::error('通知买家现货核实失败: ' . $e->getMessage(), [
                'verify_no' => $record->verify_no,
                'cart_stock_id' => $record->id ?? null,
            ]);
        }
    }

    private function resolveBuyerOrg(int $buyerId): array
    {
        $buyer = User::find($buyerId);
        if (!$buyer) {
            return [];
        }

        $member = $buyer->orgMembers()->with('org')->find();
        if (!$member || !$member->org) {
            return [];
        }

        return ['org_id' => $member->org->id];
    }

    private function normalizeMedia($media): array
    {
        if (empty($media)) {
            return [];
        }

        if (!is_array($media)) {
            return [$media];
        }

        return array_values(array_filter($media, static fn($item) => $item !== null && $item !== ''));
    }

    private function formatMediaOutput($media): array
    {
        $media = $this->normalizeMedia($media);
        $images = [];
        $videos = [];

        foreach ($media as $item) {
            $extension = strtolower(pathinfo((string) $item, PATHINFO_EXTENSION));
            if (in_array($extension, ['mp4', 'mov', 'avi', 'webm'], true)) {
                $videos[] = (string) $item;
            } else {
                $images[] = (string) $item;
            }
        }

        return [
            'images' => $images,
            'videos' => $videos,
        ];
    }

    private function statusLabel(int $status): string
    {
        return match ($status) {
            CartStock::STATUS_PENDING => '待核实',
            CartStock::STATUS_VERIFIED => '已核实',
            CartStock::STATUS_REJECTED => '已拒绝',
            CartStock::STATUS_CANCELLED => '已取消',
            default => '未知',
        };
    }
}
